package au.edu.unsw.editingtool.authentication;

import java.io.IOException;
import java.util.Hashtable;
import java.util.Iterator;

import edu.vt.middleware.ldap.Authenticator;
import edu.vt.middleware.ldap.Ldap;
import edu.vt.middleware.ldap.ldif.*;
import edu.vt.middleware.ldap.ldif.util.Ldif;
import edu.vt.middleware.ldap.LdapConfig;

import au.edu.unsw.editingtool.global.EditingToolException;
import au.edu.unsw.editingtool.global.PropertyReader;
import au.edu.unsw.editingtool.global.Util;
import au.edu.unsw.editingtool.global.GlobalConstant;

import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.SearchResult;

public class LDAP {
	
	// Hashtable containing user information
    private Hashtable<String, String> attributes;
    
    private boolean authenticated;

    private String propertyFile = "";
    
    // Get user information
    public Hashtable<String, String> getAttributes() {
        return this.attributes;
    }

    // Set user information
    public void setAttributes(Hashtable<String, String> attributes) {
        this.attributes = attributes;
    }

    // Check if the login is valid
    public boolean isValid() {
        return this.authenticated;
    }
    
    public boolean isAttributesEmpty() {
    	if(this.attributes == null){
    		return true;
    	}    	
    	if(this.attributes.isEmpty()){
    		return true;
    	}    		
        return false;
    }

    // Set the LDAP login response
    public void setValid(boolean result) {
        this.authenticated = result;
    }
    
	public void setPropertyFile(String file) {
		this.propertyFile = file;
	}
	
    public boolean authenticate(String username, String password) {
               
        PropertyReader reader = new PropertyReader();
        edu.vt.middleware.ldap.LdapConfig ldapConfig = new edu.vt.middleware.ldap.LdapConfig();
        
        reader.setFile(this.propertyFile);
        reader.setFilter(GlobalConstant.LDAP);
        try {
			reader.retrieveProperties();
		} catch (IOException e) {
			EditingToolException ex = new EditingToolException();
			ex.setMessage("Getting Error When Process Property File.");
			e.printStackTrace();
		}
        
        Hashtable<String, String> properties = reader.getProperties();
        
        ldapConfig.setHost(properties.get("host"));
        ldapConfig.setPort(properties.get("port"));
        ldapConfig.setBase(properties.get("basedn"));
        
        
        /*
        if(properties.get("TLS").trim().length() != 0)
        	ldapConfig.setBase(properties.get("TLS"));
        
        if(properties.get("SSL").trim().length() != 0)
        	ldapConfig.setBase(properties.get("SSL"));
        */                        
        
              
        /*
        try{        	
        	Ldap ld = new Ldap(ldapConfig);  
        	
        	// Test if we can connect to the LDAP server
	        if(ld.connect())
	        {
	        	System.out.println("LDAP CONNECTION SUCCESS! TRY TO AUTHENTICATE");
	        	String filter = "uid="+username;
	        	(new Ldif()).outputLdif(ld.search(filter), System.out);	        	
	        	ld.close();	        
	        		        		        	
	        	String newdn = "uid="+username+","+properties.get("basedn");	            
	            ldapConfig.setServiceCredential(password);
	            ldapConfig.setBase(newdn);
	            ld = new Ldap(ldapConfig);	            
	            
	            // Reconnect with authentication
	        	if(ld.connect())
	        	{
	        		System.out.println("LDAP AUTHENTICATION SUCCESS!!!");
	        	}
	        	else
	        	{
	        		System.out.println("LDAP AUTHENTICATION FAILED!!!");
	        	}	   
	        	// Get the user info
	        	(new Ldif()).outputLdif(ld.search(properties.get("basedn"),filter), System.out);
	        	//System.out.println("ATTRIBUTES SIZE = "+attr.size());
	        }
	        else
	        {
	        	System.out.println("LDAP CONNECTION FAILED!");
	        }
        }
        catch(Exception EX)
        {
        	EX.printStackTrace();
        }
        */
        //result.output(result.createLdif(Realldap.search(query, null), System.out);        
        System.out.println("AUTHENTICATOR START!");
        Authenticator authenticator = new Authenticator(ldapConfig);
        if (properties.get("authorizationFilter").trim().length() != 0)
        	authenticator.setAuthorizationFilter(properties.get("authorizationFilter"));
        
        authenticator.setSubtreeSearch(properties.get("subtreeSearch").equals("true"));
        authenticator.setUserField(properties.get("filter"));
        authenticator.setUser(username);
        authenticator.setCredential(password);
        
        try {
        	//authenticator.useTls(false);
        	
        	this.authenticated = authenticator.authenticate(username,password);        	
        	                        	        	
        	//if ((this.authenticated) && (properties.get("attributes").length() != 0)) {
        	if (this.authenticated) {
        		Hashtable<String, String> attributes = (Hashtable<String, String>) Util.splitString(properties.get("attributes"), ",", new Hashtable<String, String>());
        		//this.attributes = retrieveAttributes(ldapConfig, properties.get("filter"), username, password, attributes);
        	}        	           
        } 
        catch (Exception e) {
        	EditingToolException ex = new EditingToolException();
        	ex.setMessage("Getting Error When Using LDAP Authentication.");
        	e.printStackTrace();
        }
        
        System.out.println("AUTHENTICATION : "+this.authenticated);      
        System.out.println("AUTHENTICATOR END!");
        return this.authenticated;
    }
    
    private Hashtable<String, String> retrieveAttributes(LdapConfig ldapConfig, 
    													 String userField,
    													 String user,
    													 String credential,
    													 Hashtable<String, String> keys) throws Exception {
    	Hashtable<String, String> result = new Hashtable<String, String>();
    	
    	Ldap ldap = new Ldap(ldapConfig);
    	    	
    	Iterator results = ldap.search(userField + "=" + user);        	
    	
    	System.out.println("ldap.search!!!");
    	while (results.hasNext()) 
    	{
    		System.out.println("results.hasNext!!!");
    		SearchResult searchresult = (SearchResult) results.next();
    		NamingEnumeration allAttributes = searchresult.getAttributes().getAll();
    		System.out.println(searchresult.toString());
    		System.out.println(allAttributes.toString());
    		
    		while(allAttributes.hasMore()) 
    		{
    			System.out.println("results.hasMore!!!");
    			Attribute current = (Attribute) allAttributes.next();
    			NamingEnumeration values = current.getAll();
    			System.out.println("LDAP: "+current.getID()+" = "+values.next().toString());
    			if(keys.isEmpty())
    			{    				
					while (values.hasMore()) 
					{
						result.put(current.getID(), values.next().toString());						
					}
    			}
    			else if (keys.containsKey(current.getID())) 
    			{    					
    				while (values.hasMore()) 
    				{
    					result.put(current.getID(), values.next().toString());
    				}
    			}    			
    		}
    	}

    	return result;
    }
    
}